package com.zrc.japktool.util;

import pxb.android.Res_value;
import pxb.android.axml.Axml;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

public class AxmlUtil {
    /**
     * 在字节级别替换二进制AXML文件中的资源ID
     * 避免使用AxmlWriter，直接修改字节数据
     * 
     * @param xmlData 原始的二进制AXML数据
     * @param idMap 资源ID映射表 (oldId -> newId)
     * @return 修改后的二进制AXML数据
     */
    public static byte[] replaceResourceIdsInBytes(byte[] xmlData, Map<String, String> idMap) {
        if (xmlData == null || xmlData.length < 8 || idMap == null || idMap.isEmpty()) {
            return xmlData;
        }
        
        // 复制数据，避免修改原始数组
        byte[] result = xmlData.clone();
        
        // 遍历整个文件，查找和替换资源ID
        // 资源ID通常以4字节小端序存储
        for (int i = 0; i <= result.length - 4; i++) {
            // 读取当前位置的4字节作为整数（小端序）
            int currentValue = (result[i] & 0xFF) | 
                             ((result[i + 1] & 0xFF) << 8) | 
                             ((result[i + 2] & 0xFF) << 16) | 
                             ((result[i + 3] & 0xFF) << 24);
            
            // 检查这个值是否是需要替换的资源ID
            String currentHex = String.format("0x%08x", currentValue);
            if (idMap.containsKey(currentHex)) {
                String newHex = idMap.get(currentHex);
                try {
                    int newValue = Integer.decode(newHex);
                    // 替换为新的资源ID（小端序）
                    result[i] = (byte) (newValue & 0xFF);
                    result[i + 1] = (byte) ((newValue >> 8) & 0xFF);
                    result[i + 2] = (byte) ((newValue >> 16) & 0xFF);
                    result[i + 3] = (byte) ((newValue >> 24) & 0xFF);
                    System.out.printf("字节级别替换资源ID: %s --> %s (位置: %d)%n", currentHex, newHex, i);
                } catch (NumberFormatException e) {
                    // 忽略无效的ID格式
                }
            }
        }
        
        return result;
    }
    
    // 支持根据映射表替换不同ID的版本
    public static void traverseAndModifyNodes(List<Axml.Node> nodes, Map<String, String> idMap) {
        if (nodes == null || nodes.isEmpty() || idMap == null || idMap.isEmpty()) {
            return;
        }
        for (Axml.Node node : nodes) {
            if (node.attrs != null) {
                for (Axml.Node.Attr attr : node.attrs) {
                    Res_value value = attr.value;
                    // 同时支持 TYPE_REFERENCE 和 TYPE_ATTRIBUTE 两种资源引用类型
                    if (value != null && (value.type == Res_value.TYPE_REFERENCE || value.type == Res_value.TYPE_ATTRIBUTE)) {
                        String dataHex = String.format("0x%08x", value.data);
                        if (idMap.containsKey(dataHex)) {
                            String replacementHex = idMap.get(dataHex);
                            int newData = Integer.decode(replacementHex);
                            value.data = newData;
                            String typeName = value.type == Res_value.TYPE_REFERENCE ? "REFERENCE" : "ATTRIBUTE";
                            System.out.printf("修改xml中的id--> 替换属性值: %s --> %s (类型: %s)%n", dataHex, replacementHex, typeName);
                        }
                    }
                }
            }
            traverseAndModifyNodes(node.children, idMap);
        }
    }

    // 1. 修复二进制AXML识别逻辑
    public static boolean isBinaryXml(byte[] xmlData) {
        // 基础校验：数据长度至少4字节（文件头长度），排除空数据
        if (xmlData == null || xmlData.length < 4) {
            System.out.println("XML数据长度不足4字节，判定为非二进制AXML");
            return false;
        }

        // 关键：Android二进制AXML标准文件头（小端字节序）：0x03 0x00 0x08 0x00
        // 对应字节数组：[3, 0, 8, 0]，直接按字节匹配（避免字节序转换错误）
        byte[] binaryXmlHeader = {0x03, 0x00, 0x08, 0x00};
        boolean isStandardHeader = true;
        for (int i = 0; i < 4; i++) {
            if (xmlData[i] != binaryXmlHeader[i]) {
                isStandardHeader = false;
                break;
            }
        }

        // 2. 兜底校验：排除普通文本XML（如以"<?xml"开头的文本）
        if (!isStandardHeader) {
            // 读取前10个字节判断是否为文本XML（避免UTF-8 BOM干扰）
            int checkLen = Math.min(xmlData.length, 10);
            String prefix = new String(xmlData, 0, checkLen, StandardCharsets.UTF_8).trim();
            if (prefix.startsWith("<?xml") || prefix.startsWith("<")) {
                System.out.println("XML以'<?xml'或'<'开头，判定为文本XML");
            } else {
                System.out.println("非标准文件头，判定为非二进制AXML");
            }
            return false;
        }

        // 3. 额外校验：二进制AXML后续字节通常有固定结构（可选，增强准确性）
        // （可选）校验第5-8字节是否为"文件大小"（非必须，但可减少误判）
        if (xmlData.length >= 8) {
            // 第5-8字节是AXML文件大小（小端），需与实际数据长度匹配
            int xmlFileSize = (xmlData[4] & 0xFF) |
                    ((xmlData[5] & 0xFF) << 8) |
                    ((xmlData[6] & 0xFF) << 16) |
                    ((xmlData[7] & 0xFF) << 24);
            if (xmlFileSize != xmlData.length) {
                System.out.printf("二进制AXML文件大小不匹配（解析:%d，实际:%d），判定为非标准二进制AXML%n",
                        xmlFileSize, xmlData.length);
                return false;
            }
        }

        System.out.println("匹配标准二进制AXML文件头，判定为二进制AXML");
        return true;
    }

    /**
     * 获取节点的android:xxx属性值
     */
    public static String getAndroidAttrValue(Axml.Node node, String attrName) {
        String androidNs = "http://schemas.android.com/apk/res/android";
        if (node.attrs != null) {
            for (Axml.Node.Attr attr : node.attrs) {
                if (androidNs.equals(attr.ns) && attrName.equals(attr.name)) {
                    return attr.value != null ? attr.value.raw : null;
                }
            }
        }
        return null;
    }

    /**
     * 判断两个节点是否为相同节点（根据节点类型匹配关键属性）
     */
    public static boolean isSameNode(Axml.Node a, Axml.Node b) {
        switch (a.name) {
            case "uses-permission":
            case "permission":
            case "permission-group":
            case "permission-tree":
                return equals(getAndroidAttrValue(a, "name"), getAndroidAttrValue(b, "name"));// 权限类节点通过android:name区分
            case "activity":
            case "service":
            case "receiver":
            case "provider":
            case "activity-alias":
                return equals(getAndroidAttrValue(a, "name"), getAndroidAttrValue(b, "name"));// 组件类节点通过android:name区分
            case "meta-data":
                // 对于meta-data节点，优先通过android:name属性判断，如果没有name属性则通过value属性判断
                String aName = getAndroidAttrValue(a, "name");
                String bName = getAndroidAttrValue(b, "name");
                if (aName != null && bName != null) {
                    return equals(aName, bName);
                }
                // 如果没有name属性，则通过value属性判断
                String aValue = getAndroidAttrValue(a, "value");
                String bValue = getAndroidAttrValue(b, "value");
                return equals(aValue, bValue);
            case "intent-filter":
                return true; // 简单处理：认为同层级同类型intent-filter为相同节点（复杂场景需对比action/category等）
            case "application":
                return true; // 整个Manifest通常只有一个application节点
            default:
                return true; // 其他节点默认按名称+命名空间判断
        }
    }

    /**
     * 安全的字符串相等判断（处理null）
     */
    public static boolean equals(String a, String b) {
        if (a == null && b == null) return true;
        if (a == null || b == null) return false;
        return a.equals(b);
    }

    /**
     * 在A的父节点中查找与B子节点相同的节点
     * 相同定义：命名空间+节点名+关键属性匹配
     */
    public static Axml.Node findExistingChild(Axml.Node aParent, Axml.Node bChild) {
        for (Axml.Node aChild : aParent.children) {
            // 先匹配命名空间和节点名
            if (equals(aChild.ns, bChild.ns) && equals(aChild.name, bChild.name)) {
                // 再根据节点类型匹配关键属性
                if (AxmlUtil.isSameNode(aChild, bChild)) {
                    return aChild;
                }
            }
        }
        return null;
    }

    /**
     * 复制节点（包括属性、文本和子节点）
     */
    public static Axml.Node copyNode(Axml.Node source) {
        Axml.Node dest = new Axml.Node();
        dest.ns = source.ns;
        dest.name = source.name;
        dest.ln = source.ln;

        // 复制文本内容
        if (source.text != null) {
            Axml.Node.Text destText = new Axml.Node.Text();
            destText.ln = source.text.ln;
            destText.text = source.text.text;
            destText.styled = source.text.styled;
            dest.text = destText;
        }

        // 复制属性
        if (source.attrs != null) {
            for (Axml.Node.Attr sourceAttr : source.attrs) {
                Axml.Node.Attr destAttr = new Axml.Node.Attr();
                destAttr.ns = sourceAttr.ns;
                destAttr.name = sourceAttr.name;
                destAttr.resourceId = sourceAttr.resourceId;
                destAttr.value = sourceAttr.value;
                destAttr.raw = sourceAttr.raw;
                dest.attrs.add(destAttr);
            }
        }

        // 递归复制子节点
        if (source.children != null) {
            for (Axml.Node sourceChild : source.children) {
                dest.children.add(copyNode(sourceChild));
            }
        }

        return dest;
    }

}
